package com.fauks.gmall.manager.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.fauks.gmall.bean.PmsSkuImage;
import com.fauks.gmall.bean.PmsSkuInfo;
import com.fauks.gmall.manager.mapper.PmsSkuImageMapper;
import com.fauks.gmall.manager.mapper.SkuMapper;
import com.fauks.gmall.service.SkuService;
import com.fauks.gmall.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;

import java.util.List;
import java.util.UUID;

@Service
public class SkuServiceImpl implements SkuService {

    @Autowired
    private SkuMapper skuMapper;

    @Autowired
    private PmsSkuImageMapper skuImageMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public PmsSkuInfo getSkuById(String skuId, String clientIp) {
        System.out.println("【查询sku】【" + clientIp + "】进入查询-" + Thread.currentThread().getName());
        PmsSkuInfo pmsSkuInfo;
        Jedis jedis = redisUtils.getJedis();
        //自定义sku info的key
        String skuKey = "sku:" + skuId + ":info";
        String skuInfoStr = jedis.get(skuKey);
        if (!StringUtils.isEmpty(skuInfoStr)) {
            //缓存存在
            System.out.println("【查询sku】【" + clientIp + "】获取到缓存数据-" + Thread.currentThread().getName());
            pmsSkuInfo = JSON.parseObject(skuInfoStr, PmsSkuInfo.class);
        } else {
            //缓存不存在查找DB
            //为了防止缓存击穿需要使用redis分布式锁，限制数据库的访问
            String redisLockKey = "sku:" + skuId + ":lock";
            //如果不存在锁则返回OK
            String redisLockValue = UUID.randomUUID().toString();
            String OK = jedis.set(redisLockKey, redisLockValue, "nx", "ex", 10 * 1000);
            if (!StringUtils.isEmpty(OK) && OK.equals("OK")) {
                System.out.println("【查询sku】【" + clientIp + "】获取到Redis锁查询DB-" + Thread.currentThread().getName());
                //可以正常访问数据库
                pmsSkuInfo = getSkuByIdFromDB(skuId);
                if (pmsSkuInfo != null) {
                    //数据库中存在商品信息写入redis
                    jedis.set(skuKey, JSON.toJSONString(pmsSkuInfo));
                } else {
                    //数据库不存在要查询的信息，为了防止缓存穿透需要设置特殊字符串并设置过期时间
                    jedis.setex(skuKey, 60 * 3, JSON.toJSONString(""));
                }
                //执行成功后释放redis锁
                //判断是否是自己的锁
                String getRedisLockValue = jedis.get(redisLockKey);
                if (!StringUtils.isEmpty(getRedisLockValue) && redisLockValue.equals(getRedisLockValue)) {
                    //是当前线程的redis锁则可以删除
                    jedis.del(redisLockKey);
                }
                System.out.println("【查询sku】【" + clientIp + "】释放Redis锁-" + Thread.currentThread().getName());
            } else {
                //等待释放锁而进行自旋
                System.out.println("【查询sku】【" + clientIp + "】进行自旋-" + Thread.currentThread().getName());
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return getSkuById(skuId, clientIp);
            }
        }
        return pmsSkuInfo;
    }

    @Override
    public List<PmsSkuInfo> getSkuSaleAttrMapBySpu(String productId) {
        return skuMapper.selectSkuSaleAttrMapBySpu(productId);
    }

    /**
     * 缓存不存在查找数据库
     *
     * @param skuId
     * @return
     */
    private PmsSkuInfo getSkuByIdFromDB(String skuId) {
        PmsSkuInfo pmsSkuInfo = new PmsSkuInfo();
        pmsSkuInfo.setId(skuId);
        PmsSkuInfo skuInfo = skuMapper.selectOne(pmsSkuInfo);
        if (skuInfo != null) {
            PmsSkuImage skuImage = new PmsSkuImage();
            skuImage.setSkuId(skuId);
            List<PmsSkuImage> skuImageList = skuImageMapper.select(skuImage);
            skuInfo.setPmsSkuImageList(skuImageList);
        }
        return skuInfo;
    }
}
